package net.maku.infra.biz.service.file.impl;


import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.maku.commons.biza.util.JsonUtils;
import net.maku.commons.biza.util.ValidationUtils;
import net.maku.infra.biz.controller.file.vo.FileConfigCreateReqVO;
import net.maku.infra.biz.controller.file.vo.FileConfigPageReqVO;
import net.maku.infra.biz.controller.file.vo.FileConfigUpdateReqVO;
import net.maku.infra.biz.core.file.FileClient;
import net.maku.infra.biz.core.file.FileClientConfig;
import net.maku.infra.biz.core.file.FileClientFactory;
import net.maku.infra.biz.core.file.enums.FileStorageEnum;
import net.maku.infra.biz.mapper.file.InfraFileConfigMapper;
import net.maku.infra.biz.mq.producer.FileConfigProducer;
import net.maku.infra.biz.pojo.file.InfraFileConfigPojo;
import net.maku.infra.biz.service.file.FileConfigService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.validation.annotation.Validated;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.validation.Validator;
import java.util.List;
import java.util.Map;

/**
 * 文件配置 Service 实现类
 *
 * @author 哈博智能
 */
@Service
@Validated
@Slf4j
public class FileConfigServiceImpl implements FileConfigService {

    @Resource
    private FileClientFactory fileClientFactory;

    @Getter
    private FileClient masterFileClient;

    @Resource
    private InfraFileConfigMapper fileConfigMapper;

    @Resource
    private FileConfigProducer fileConfigProducer;

    @Resource
    private Validator validator;

    @Override
    @PostConstruct
    public void initLocalCache() {
        // 第一步：查询数据
        List<InfraFileConfigPojo> configs = fileConfigMapper.selectList();
        log.info("[initLocalCache][缓存文件配置，数量为:{}]", configs.size());

        // 第二步：构建缓存：创建或更新文件 Client
        configs.forEach(config -> {
            fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig());
            // 如果是 master，进行设置
            if (Boolean.TRUE.equals(config.getMaster())) {
                masterFileClient = fileClientFactory.getFileClient(config.getId());
            }
        });
    }

    @Override
    public Long createFileConfig(FileConfigCreateReqVO createReqVO) {

        // 插入
        InfraFileConfigPojo fileConfig = Convert.convert(InfraFileConfigPojo.class,createReqVO);
        fileConfig.setConfig(parseClientConfig(createReqVO.getStorage(), createReqVO.getConfig()));
        fileConfig.setMaster(false);
        fileConfigMapper.insert(fileConfig);
        // 发送刷新配置的消息
        fileConfigProducer.sendFileConfigRefreshMessage();
        // 返回
        return fileConfig.getId();
    }

    @Override
    public void updateFileConfig(FileConfigUpdateReqVO updateReqVO) {
        // 校验存在
        try{
            InfraFileConfigPojo config = validateFileConfigExists(updateReqVO.getId());
            config.setConfig(parseClientConfig(config.getStorage(), updateReqVO.getConfig()));
            fileConfigMapper.updateById(config);
            // 发送刷新配置的消息
            fileConfigProducer.sendFileConfigRefreshMessage();
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateFileConfigMaster(Long id) {
        // 校验存在
        try{
            validateFileConfigExists(id);
        }catch (Exception e){
            e.printStackTrace();
        }

        // 更新其它为非 master
        InfraFileConfigPojo infraFileConfigPojo = new InfraFileConfigPojo();
        infraFileConfigPojo.setMaster(false);
        fileConfigMapper.updateBatch(infraFileConfigPojo);
        // 更新
        infraFileConfigPojo.setId(id);
        infraFileConfigPojo.setMaster(true);
        fileConfigMapper.updateById(infraFileConfigPojo);
        // 发送刷新配置的消息
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {

            @Override
            public void afterCommit() {
                fileConfigProducer.sendFileConfigRefreshMessage();
            }

        });
    }

    private FileClientConfig parseClientConfig(Integer storage, Map<String, Object> config) {
        // 获取配置类
        Class<? extends FileClientConfig> configClass = FileStorageEnum.getByStorage(storage)
                .getConfigClass();
        FileClientConfig clientConfig = JsonUtils.parseObject2(JsonUtils.toJsonString(config), configClass);
        // 参数校验
        ValidationUtils.validate(validator, clientConfig);
        // 设置参数
        return clientConfig;
    }

    @Override
    public void deleteFileConfig(Long id){
        // 校验存在
        try{
            InfraFileConfigPojo config = validateFileConfigExists(id);
            if (Boolean.TRUE.equals(config.getMaster())) {
                return;
            }
            // 删除
            fileConfigMapper.deleteById(id);
            // 发送刷新配置的消息
            fileConfigProducer.sendFileConfigRefreshMessage();
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    private InfraFileConfigPojo validateFileConfigExists(Long id) throws Exception {
        InfraFileConfigPojo config = fileConfigMapper.selectById(id);
        if (config == null) {
            throw new Exception("文件不存在！");
        }
        return config;
    }

    @Override
    public InfraFileConfigPojo getFileConfig(Long id) {
        return fileConfigMapper.selectById(id);
    }

    @Override
    public Page<InfraFileConfigPojo> getFileConfigPage(FileConfigPageReqVO pageReqVO) {
        Page<InfraFileConfigPojo> page = Page.of(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        return fileConfigMapper.selectPage(page,pageReqVO);
    }

    @Override
    public String testFileConfig(Long id) throws Exception {
        // 校验存在
        validateFileConfigExists(id);
        // 上传文件
        byte[] content = ResourceUtil.readBytes("file/erweima.jpg");
        return fileClientFactory.getFileClient(id).upload(content, IdUtil.fastSimpleUUID() + ".jpg", "image/jpeg");
    }

    @Override
    public FileClient getFileClient(Long id) {
        return fileClientFactory.getFileClient(id);
    }

}
